package mulitThread;

import java.util.concurrent.*;


/**
 * 任务分配者，Node为最小任务
 */
public class MainAssigner{
    private Thread[] ThreadChi;
    private final SynchronousQueue<Node> blockingDeque =new SynchronousQueue<>();//可替换成线程安全的任意队列
    private final Tick tick=new Tick();
    private int maxNodeNumber=0;

    public int getQueueSize(){
        return blockingDeque.size();
    }

    private boolean isAllFinish(){
        return maxNodeNumber ==tick.sum;
    }

    private boolean iswaitForFinish=false;

    /**
     * 等待全部线程结束，同步等待
     */
    public void waitForFinish(){
        iswaitForFinish=true;
        try {
            synchronized (this){
                while(!isAllFinish())this.wait();
            }
        }catch (InterruptedException e){}
        iswaitForFinish=false;
    }

    public void addNode(Node node){
        maxNodeNumber++;
        try{
            blockingDeque.put(node);
        }catch(InterruptedException e){
        }
    }

    public void run(Node node){
        node.run();
    }

    /**
     * 任务分配者，Node为最小任务
     * 请使用静态全局变量，不要作为局部变量，否则线程数量会爆炸
     * 其次，加完 node 记得调用 waitForFinish等待线程完成
     */
    public MainAssigner(int n){
        ThreadChi=new Thread[n];
        final MainAssigner thisMainAssigner=this;
        for(int i=0;i<ThreadChi.length;i++){
            ThreadChi[i]=new Thread(() -> {
                try{
                    for(;;){
                        Node node=blockingDeque.take();
                        run(node);
                        tick.add();

                        if(iswaitForFinish&&blockingDeque.isEmpty()){
                            if(node instanceof ThreadFinishNode)break;
							if(isAllFinish()){
								synchronized (thisMainAssigner) {
									this.notify();
								}
							}
                        }
                    }
                }catch(InterruptedException e){
                }
            });
            ThreadChi[i].start();
        }
    }

    /**
     * 内含 waitForFinish
     * 释放线程资源
     * 结束时使用
     */
    public void dispose(){
        waitForFinish();
        for(int i=0;i<ThreadChi.length;i++){
            blockingDeque.add(new ThreadFinishNode());
        }
    }

    static class Tick{
        int sum=0;
        public void add(){
            synchronized(this){
                sum++;
            }
        }
    }

    static class ThreadFinishNode extends Node{
        @Override
        public void run() {

        }
    }
}